package io.gitee.yxsnake.mybatis.plus.interceptor;

import io.gitee.yxsnake.embark.web.core.constant.StringPool;
import io.gitee.yxsnake.embark.web.core.exception.DataStorageException;
import io.gitee.yxsnake.embark.web.core.secret.sm.SM3Utils;
import io.gitee.yxsnake.embark.web.core.secret.sm.SM4Utils;
import io.gitee.yxsnake.mybatis.plus.annotation.SensitiveData;
import io.gitee.yxsnake.mybatis.plus.annotation.SensitiveField;
import io.gitee.yxsnake.mybatis.plus.configuration.properties.MybatisPlusExtProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.dromara.hutool.core.text.StrUtil;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.Objects;

/**
 * @author snake
 * @description
 * @since 2024/10/20 23:49
 */
@Slf4j
@Intercepts({
        @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
})
@RequiredArgsConstructor
public class DataEncryptInterceptor implements Interceptor {

    private final MybatisPlusExtProperties mybatisPlusExtProperties;

    private final String sm4Key;
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
        Field paramsFiled = parameterHandler.getClass().getDeclaredField("parameterObject");
        ReflectionUtils.makeAccessible(paramsFiled);
        Object parameterObject = paramsFiled.get(parameterHandler);
        if(Objects.nonNull(parameterObject)) {
            Class<?> parameterObjectClass = parameterObject.getClass();
            SensitiveData dbSensitiveEntity = AnnotationUtils.findAnnotation(parameterObjectClass, SensitiveData.class);
            if (Objects.nonNull(dbSensitiveEntity)) {
                //取出当前类的所有字段，传入加密方法
                Field[] declaredFields = parameterObjectClass.getDeclaredFields();
                for (Field field : declaredFields) {
                    //取出所有被DbSensitiveField注解的字段
                    SensitiveField dbSensitiveField = field.getAnnotation(SensitiveField.class);
                    if (Objects.nonNull(dbSensitiveField)) {
                        ReflectionUtils.makeAccessible(field);
                        Object object = field.get(parameterObject);
                        //这里暂时只对String类型来加密
                        if (object instanceof String) {
                            String value = (String) object;
                            String encrypt = encrypt(value);
                            field.set(parameterObject, encrypt);
                        }
                    }
                }
            }
        }
        //获取原方法的返回值
        return invocation.proceed();
    }


    /**
     * 解密
     * @param content
     * @return
     */
    private String encrypt(String content){
        String encryptContent = null;
        if(StrUtil.isBlank(content)){
            return content;
        }
        //加密数据
        String encrypt = SM4Utils.encrypt(sm4Key, content);
        // 对数据进行签名
        String signText = null;
        try {
            signText = SM3Utils.encryptText(content);
        } catch (UnsupportedEncodingException e) {
            throw new DataStorageException(500,"数据计算签名失败");
        }
        encryptContent = encrypt + StringPool.DOT + signText;
        return encryptContent;
    }
}
